import Layers from "@/lang/layers";
import {messages} from "../../lang/fast-form/messages";
import AsyncValidator from "async-validator";

/**
 * 表内输入组件有效性验证
 *
 * 目前设计还是比较简单的，如果需要验证输入是否有效，所有的逻辑都通过外部代码实现，
 *
 * 组件自身，只负责最终的数据展示，对于表单的序列化、文本变化，都需要手动触发校验。
 */
class TableValidator {

    /**
     * 给数据列表中的每一个元素，增加字段校验信息
     *
     * @param list {[]} 数据列表
     * @param rules {any} 数据校验规则
     */
    static wrap(list, rules) {
        const fields = this.getFields(rules);

        // 给数据元素设置基本校验情况
        list.forEach(item => {
            const validator = {};
            for (let i = 0; i < fields.length; i++) {
                validator[fields[i]] = {valid: undefined, message: ''};
            }
            item.$validators = validator;
        })
    }

    /**
     * 获取需要校验的字段名列表
     *
     * @param rules {any} 数据校验规则
     * @returns {[string]}
     */
    static getFields(rules) {
        // 获取所有需要校验的字段
        const fields = [];
        for (let key in rules) {
            if (rules.hasOwnProperty(key)) {
                fields.push(key);
            }
        }
        return fields;
    }

    /**
     * 清除数据列表的校验信息
     *
     * 后续业务可能是提交表单，需要清除数据校验相关的内容
     *
     * @param list {[]} 数据列表
     */
    static unpack(list) {
        list.forEach(item => {
            delete item.$validators;
        })
    }

    /**
     * 验证完整的数据列表
     *
     * @param list {[]} 数据列表
     * @param rules {any} 数据校验规则
     */
    static checkList(list, rules) {
        const fields = this.getFields(rules);
        list.forEach(item => {
            const validator = item.$validators;
            fields.forEach(key => {
                const valid = validator[key];
                const rule = rules[key];
                const value = item[key];
                this.checkValidity(value, key, rule, valid);
            })
        })
    }


    /**
     * 校验单个的数据元素
     * @param row 行级数据
     * @param rules 验证规则
     * @param key 字段名
     */
    static checkItem(row, rules, key) {
        const validator = row.$validators[key];
        if (validator.valid !== undefined) {
            const value = row[key];
            const rule = rules[key];
            this.checkValidity(value, key, rule, validator);
        }
    }

    /**
     * 数据是否非空
     *
     * @param val 数据
     * @param ret 数据校验结果
     */
    static require(val, ret) {
        if (Layers.isEmpty(val)) {
            ret.valid = false;
            ret.message = '数据不允许为空';
        }
    }

    /**
     * 比较当前值是否有效，错误信息会直接赋值到 this.message
     *
     * @param rules 数据校验规则
     * @param value 需要验证的值
     * @param label 提示用的标签值
     * @param ret   数据有效性提示
     */
    static checkValidity(value, label, rules, ret) {
        // Validator 验证
        this.checkValidityWithAsyncValidator(rules, value, label, (errors) => {
            ret.valid = !errors;
            //错误提示，这里只取第一个
            ret.message = errors ? errors[0].message : '';
        }).then(values => {
            console.log(values);
        });
    }

    /**
     * 使用 AsyncValidator 进行数据校验，代码参考自 element-ui
     *
     * @param rules 数据校验规则
     * @param value 需要验证的值
     * @param label 提示用的标签值
     * @param call 提示用的标签值
     * @return Promise<Values>
     */
    static checkValidityWithAsyncValidator(rules, value, label, call) {
        // 规则描述
        const descriptor = {};
        if (Layers.isNotEmpty(rules)) {
            rules.forEach(rule => {
                delete rule.trigger;
            });
        }
        descriptor[label] = rules;

        // 数据模型
        const validator = new AsyncValidator(descriptor);
        const model = {};
        model[label] = value;

        // 导入汉化之后的错误提示包
        validator.messages(messages);

        // 数据校验
        return validator.validate(model, {firstFields: true}, call);
    }
}

export default TableValidator;